package com.yongbao.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yongbao.common.Constants;
import com.yongbao.common.PageInfo;
import com.yongbao.common.domain.BaseEntity;
import com.yongbao.common.enums.OrderTypeEnum;
import com.yongbao.common.service.RedisService;
import com.yongbao.common.utils.AssertUtil;
import com.yongbao.context.SessionContext;
import com.yongbao.mapper.DishOrderBookMapper;
import com.yongbao.mapper.DishOrderDishMapper;
import com.yongbao.mapper.DishOrderMapper;
import com.yongbao.mapper.DishOrderSubMapper;
import com.yongbao.model.domain.*;
import com.yongbao.model.dtomapper.DishOrderDtoMapper;
import com.yongbao.model.request.DishOrderRequest;
import com.yongbao.model.request.manual.order.DishOrderBookAddRequest;
import com.yongbao.model.request.manual.order.JoinOrderAddRequest;
import com.yongbao.model.request.manual.order.MainOrderAddRequest;
import com.yongbao.model.request.manual.order.NearbyOrderRequest;
import com.yongbao.model.util.DishOrderConvert;
import com.yongbao.model.util.DishOrderDishConvert;
import com.yongbao.model.vo.DishOrderDishVO;
import com.yongbao.model.vo.DishOrderVO;
import com.yongbao.model.vo.UserVO;
import com.yongbao.model.vo.manual.DishOrderSubAreaStatisticsVO;
import com.yongbao.model.vo.manual.NearbyOrderVO;
import com.yongbao.model.vo.manual.UserBookDetailVO;
import com.yongbao.service.*;
import com.yongbao.utils.OrderNumUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhanghong
 */
@Service
public class DishOrderServiceImpl extends ServiceImpl<DishOrderMapper, DishOrderDO> implements DishOrderService {
    @Autowired
    private DishOrderMapper dishOrderMapper;
    @Autowired
    private DishOrderSubMapper dishOrderSubMapper;
    @Autowired
    private DishOrderDishMapper dishOrderDishMapper;
    @Autowired
    private DishOrderDishService dishOrderDishService;
    @Autowired
    private DishOrderBookMapper dishOrderBookMapper;
    @Autowired
    private DishService dishService;
    @Autowired
    private DishOrderSubService dishOrderSubService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private DishOrderBookService dishOrderBookService;
    @Autowired
    private UserService userService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs;
    @Autowired
    private DishSpecificationService dishSpecificationService;

    @Override
    public DishOrderVO getByKey(long id) {
        DishOrderVO dishOrderVO = DishOrderDtoMapper.INSTANCE.do2VO(getById(id));
        fillInfo(dishOrderVO);
        return dishOrderVO;
    }

    @Override
    public PageInfo<DishOrderVO> pageQuery(DishOrderRequest request) {
        fillParam(request);
        long count = dishOrderMapper.pageCount(request);
        List<DishOrderDO> list = dishOrderMapper.pageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<DishOrderVO> dishOrderVOList = DishOrderConvert.buildDishOrderVoList(list);
        for (DishOrderVO dishOrderVO : dishOrderVOList) {
            fillInfo(dishOrderVO);
        }
        return new PageInfo(request.getPageNum(), request.getPageSize(), dishOrderVOList, count);
    }

    private void fillParam(DishOrderRequest request) {
        if (request.getStatisticsType() != null) {
            Date startTime = new Date();
            Date endTime = new Date();
            Date date = new Date();
            if (request.getStatisticsType() == 1) {
                DateTime dateTime = DateUtil.offsetDay(date, -1);
                startTime = DateUtil.beginOfDay(dateTime);
                endTime = DateUtil.endOfDay(dateTime);
            }
            if (request.getStatisticsType() == 2) {
                DateTime dateTime = DateUtil.offsetDay(date, -2);
                startTime = DateUtil.beginOfDay(dateTime);
                endTime = DateUtil.endOfDay(dateTime);
            }
            if (request.getStatisticsType() == 3) {
                DateTime dateTime = DateUtil.offsetDay(date, -7);
                startTime = DateUtil.beginOfDay(dateTime);
                endTime = date;
            }
            if (request.getStatisticsType() == 4) {
                DateTime dateTime = DateUtil.offsetDay(date, -30);
                startTime = DateUtil.beginOfDay(dateTime);
                endTime = date;
            }
            request.setStartCreateTime(startTime);
            request.setEndCreateTime(endTime);
        }
    }

    private void fillInfo(DishOrderVO dishOrderVO) {
        // 查询菜品集合
        List<DishOrderDishDO> dishList = dishOrderDishService.lambdaQuery().eq(DishOrderDishDO::getOrderId, dishOrderVO.getId()).list();
        if (CollectionUtils.isNotEmpty(dishList)) {
            List<DishOrderDishVO> dishOrderDishVOList = DishOrderDishConvert.buildDishOrderDishVoList(dishList);
            for (DishOrderDishVO item : dishOrderDishVOList) {
                DishDO dishDO = dishService.lambdaQuery().eq(BaseEntity::getId, item.getDishId()).last("limit 1").one();
                if (dishDO != null) {
                    item.setDishName(dishDO.getDishName());
                    item.setDishImg(dishDO.getDishImg());
                }
            }
            dishOrderVO.setDishOrderDishList(dishOrderDishVOList);
        }

        // 查询订单菜品份数
        Long count = 0L;
        List<UserVO> userList = Lists.newArrayList();
        List<DishOrderSubDO> dishOrderSubDOList = dishOrderSubService.lambdaQuery().eq(DishOrderSubDO::getOrderId, dishOrderVO.getId()).list();
        for (DishOrderSubDO dishOrderSubDO : dishOrderSubDOList) {
            List<DishOrderBookDO> list = dishOrderBookService.lambdaQuery().eq(DishOrderBookDO::getOrderId, dishOrderVO.getId()).eq(DishOrderBookDO::getSubOrderId, dishOrderSubDO.getId()).list();
            for (DishOrderBookDO dishOrderBookDO : list) {
                count = count + dishOrderBookDO.getBookNum();
            }
            if (dishOrderSubDO.getHeadGroup()!=null && dishOrderSubDO.getHeadGroup() == 1) {
                userList.add(userService.getByKey(dishOrderSubDO.getUserId()));
            }
        }
        dishOrderVO.setCount(count);
        dishOrderVO.setHeadGroupList(userList);
    }

    @Override
    public List<DishOrderVO> listQuery(DishOrderRequest request) {
        List<DishOrderDO> list = dishOrderMapper.selectDOList(DishOrderDtoMapper.INSTANCE.request2DO(request));
        List<DishOrderVO> dishOrderVOS = DishOrderConvert.buildDishOrderVoList(list);
        for (DishOrderVO dishOrderVO : dishOrderVOS) {
            fillInfo(dishOrderVO);
        }
        return dishOrderVOS;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean mainOrderAdd(MainOrderAddRequest request) {
        DishOrderDO dishOrderDO = DishOrderDtoMapper.INSTANCE.request2DO(request);
        dishOrderDO.setAreaNamePrefix(StrUtil.subPre(request.getAreaName(), 2));
        dishOrderDO.setOrderNum(OrderNumUtil.createUniqueOrderNum());
        Pair<Date, Date> orderTypePair = OrderTypeEnum.getDishRange(request.getOrderType());
        AssertUtil.assertNotNull(orderTypePair, "订餐类型不能为空");
        dishOrderDO.setStartDate(orderTypePair.getLeft());
        dishOrderDO.setEndDate(orderTypePair.getRight());
        if (save(dishOrderDO)) {
            // 设置订单位置
            redisService.setGeo(Constants.MAIN_ORDER, request.getLng(), request.getLat(), dishOrderDO.getId());

            // 写入子订单
            DishOrderSubDO dishOrderSubDO = new DishOrderSubDO();
            dishOrderSubDO.setOrderId(dishOrderDO.getId());
            dishOrderSubDO.setUserId(request.getUserId());
            dishOrderSubDO.setLng(request.getLng());
            dishOrderSubDO.setLat(request.getLat());
            dishOrderSubDO.setHeadGroup(request.getHeadGroup());
            dishOrderSubDO.setMobile(request.getMobile());
            dishOrderSubDO.setCreateTime(new Date());
            dishOrderSubDO.setCreateUser(request.getUserId());
            dishOrderSubMapper.insertDO(dishOrderSubDO);
            if (request.getHeadGroup()!=null && request.getHeadGroup() == 1) {
                userService.lambdaUpdate().set(UserDO::getHeadGroup, request.getHeadGroup()).eq(BaseEntity::getId, request.getUserId()).update();
            }

            // 写入订单菜单表
            for (DishOrderBookAddRequest item : request.getBookList()) {
                // 订单菜品表
                DishOrderDishDO dishOrderDishDO = new DishOrderDishDO();
                dishOrderDishDO.setOrderId(dishOrderDO.getId());
                dishOrderDishDO.setDishId(item.getDishId());
                dishOrderDishDO.setCreateTime(new Date());
                dishOrderDishDO.setCreateUser(request.getUserId());
                dishOrderDishMapper.insertDO(dishOrderDishDO);

                AssertUtil.assertNotNull(item.getBookNum(), "预定分数不能为空");
                AssertUtil.assertTrue(item.getBookNum() > 0, "预定份数至少一份起");

                // 人员预定菜品数量表
                DishOrderBookDO dishOrderBookDO = new DishOrderBookDO();
                dishOrderBookDO.setOrderId(dishOrderDO.getId());
                dishOrderBookDO.setSubOrderId(dishOrderSubDO.getId());
                dishOrderBookDO.setDishId(item.getDishId());
                dishOrderBookDO.setBookNum(item.getBookNum());
                dishOrderBookDO.setCreateTime(new Date());
                dishOrderBookDO.setCreateUser(request.getUserId());
                dishOrderBookMapper.insertDO(dishOrderBookDO);
            }
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean joinGroupAdd(JoinOrderAddRequest request) {
        DishOrderDO dishOrderDO = dishOrderMapper.selectDOById(request.getOrderId());
        AssertUtil.assertNotNull(dishOrderDO, "主订单不存在");

        // 写入子订单
        DishOrderSubDO dishOrderSubDO = new DishOrderSubDO();
        dishOrderSubDO.setOrderId(dishOrderDO.getId());
        dishOrderSubDO.setUserId(request.getUserId());
        dishOrderSubDO.setLng(request.getLng());
        dishOrderSubDO.setLat(request.getLat());
        dishOrderSubDO.setHeadGroup(request.getHeadGroup());
        dishOrderSubDO.setMobile(request.getMobile());
        dishOrderSubDO.setCreateUser(request.getUserId());
        if (dishOrderSubMapper.insertDO(dishOrderSubDO) == 1) {
            if (request.getHeadGroup()!=null && request.getHeadGroup() == 1) {
                userService.lambdaUpdate().set(UserDO::getHeadGroup, request.getHeadGroup()).eq(BaseEntity::getId, request.getUserId()).update();
            }

            // 人员预定菜品数量表
            for (DishOrderBookAddRequest item : request.getBookList()) {
                DishOrderBookDO dishOrderBookDO = new DishOrderBookDO();
                dishOrderBookDO.setOrderId(dishOrderDO.getId());
                dishOrderBookDO.setSubOrderId(dishOrderSubDO.getId());
                dishOrderBookDO.setDishId(item.getDishId());
                dishOrderBookDO.setBookNum(item.getBookNum());
                dishOrderBookDO.setCreateTime(new Date());
                dishOrderBookDO.setCreateUser(request.getUserId());
                dishOrderBookMapper.insertDO(dishOrderBookDO);
            }
        }
        return true;
    }

    @Override
    public Boolean updateByKey(DishOrderRequest request) {
        AssertUtil.assertNotNull(request.getId(), "id不能为空");
        saveOrUpdate(DishOrderDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    public Boolean delByKey(String ids) {
        dishOrderMapper.deleteDOByIds(Convert.toStrArray(ids));
        return true;
    }

    @Override
    public List<UserBookDetailVO> bookDetail() {
        Long wechatUserId = SessionContext.getLoginAccountId();
        AssertUtil.assertNotNull(wechatUserId, "未登录");
        DishOrderDO dishOrderDO = dishOrderMapper.queryRecentCreatUserId(wechatUserId);
        if (dishOrderDO == null) {
            return Collections.emptyList();
        }

        DishOrderDishDO dishOrderDishDO = dishOrderDishService.lambdaQuery().eq(DishOrderDishDO::getOrderId, dishOrderDO.getId()).last("limit 1").one();
        if (dishOrderDishDO == null) {
            return Collections.emptyList();
        }

        List<DishSpecificationDO> dishSpecificationDOList = dishSpecificationService.lambdaQuery().eq(DishSpecificationDO::getDishId, dishOrderDishDO.getDishId()).list();
        if (CollectionUtils.isEmpty(dishSpecificationDOList)) {
            return Collections.emptyList();
        }

        // 统计份数
        Integer count = 0;
        List<DishOrderSubDO> dishOrderSubDOList = dishOrderSubService.lambdaQuery().eq(DishOrderSubDO::getOrderId, dishOrderDO.getId()).list();
        for (DishOrderSubDO dishOrderSubDO : dishOrderSubDOList) {
            List<DishOrderBookDO> list = dishOrderBookService.lambdaQuery().eq(DishOrderBookDO::getOrderId, dishOrderDO.getId()).eq(DishOrderBookDO::getSubOrderId, dishOrderSubDO.getId()).list();
            for (DishOrderBookDO dishOrderBookDO : list) {
                count = count + dishOrderBookDO.getBookNum().intValue();
            }
        }

        // 计算价格
        BigDecimal sellPrice = null;
        List<DishSpecificationDO> dishSpecificationList = dishSpecificationDOList.stream().sorted(Comparator.comparing(DishSpecificationDO::getAvailablePersons)).collect(Collectors.toList());
        DishSpecificationDO pre = null;
        for (DishSpecificationDO dishSpecificationDO : dishSpecificationList) {
            if (count < dishSpecificationDO.getAvailablePersons()) {
                if (pre == null) {
                    pre = dishSpecificationDO;
                }
                sellPrice = pre.getSellPrice();
                break;
            } else {
                pre = dishSpecificationDO;
            }
        }

        List<UserBookDetailVO> userBookDetailList = Lists.newArrayList();
//        Long joinNum = dishOrderSubService.lambdaQuery().eq(DishOrderSubDO::getOrderId, dishOrderDO.getId()).count();
        Long joinNum = dishOrderBookMapper.sumDish(dishOrderDO.getId());
        if (dishOrderDO.getBookBreakfast() != null && dishOrderDO.getBookBreakfast() == 1) {
            UserBookDetailVO book = new UserBookDetailVO();
            book.setBookType("早餐");
            book.setBookPrice(sellPrice);
            book.setJoinNum(joinNum);
            userBookDetailList.add(book);
        }
        if (dishOrderDO.getBookLunch() != null && dishOrderDO.getBookLunch() == 1) {
            UserBookDetailVO book = new UserBookDetailVO();
            book.setBookType("中午餐");
            book.setBookPrice(sellPrice);
            book.setJoinNum(joinNum);
            userBookDetailList.add(book);
        }
        if (dishOrderDO.getBookDinner() != null && dishOrderDO.getBookDinner() == 1) {
            UserBookDetailVO book = new UserBookDetailVO();
            book.setBookType("下午餐");
            book.setBookPrice(sellPrice);
            book.setJoinNum(joinNum);
            userBookDetailList.add(book);
        }
        return userBookDetailList;
    }

    @Override
    public NearbyOrderVO nearbyOrder(NearbyOrderRequest request) {
        NearbyOrderVO nearbyOrderVO = new NearbyOrderVO();

        // 查询500m范围内的订单
        Distance distance = new Distance(0.5, Metrics.KILOMETERS);
        Circle circle = new Circle(new Point(Double.parseDouble(request.getLng()), Double.parseDouble(request.getLat())), distance);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = redisTemplate.opsForGeo().radius(Constants.MAIN_ORDER, circle, geoRadiusCommandArgs);

        Long dishCount = 0L;
        List<NearbyOrderVO.TakeVO> takeVOList = Lists.newArrayList();
        for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult : geoResults) {
            // 查询订单
            String orderId = geoResult.getContent().getName();
            DishOrderDO dishOrderDO = dishOrderMapper.selectDOById(Long.parseLong(orderId));
            if (dishOrderDO == null) {
                continue;
            }
            double distanceInm = geoResult.getDistance().getValue() * 1000;
            NearbyOrderVO.TakeVO takeVO = new NearbyOrderVO.TakeVO();
            takeVO.setOrderId(Long.parseLong(orderId));
            takeVO.setDistance(NumberUtil.round(distanceInm, 1).doubleValue());
            takeVO.setAddress(dishOrderDO.getAddress());
            takeVO.setAddressPrefix(StrUtil.subPre(dishOrderDO.getAddress(), 2));
            takeVOList.add(takeVO);

            List<DishOrderBookDO> list = dishOrderBookService.lambdaQuery().eq(DishOrderBookDO::getOrderId, dishOrderDO.getId()).list();
            for (DishOrderBookDO dishOrderBookDO : list) {
                dishCount = dishCount + dishOrderBookDO.getBookNum();
            }
        }
        nearbyOrderVO.setOrderCount(takeVOList.size());
        nearbyOrderVO.setDishCount(dishCount);
        nearbyOrderVO.setTakeList(takeVOList);
        return nearbyOrderVO;
    }

    @Override
    public List<DishOrderSubAreaStatisticsVO> areaStatistics(DishOrderRequest request) {
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.listQuery(request);
        if (CollectionUtils.isEmpty(dishOrderDOS)) {
            return Collections.emptyList();
        }
        List<DishOrderSubAreaStatisticsVO> dishOrderSubAreaStatisticsVOS = Lists.newArrayList();
        dishOrderDOS.stream().map(item->{
            String areaName = item.getAreaName();
            if (StringUtils.isBlank(item.getAreaNamePrefix())) {
                item.setAreaNamePrefix(StrUtil.subPre(areaName, 2));
            }
            return item;
        }).collect(Collectors.groupingBy(DishOrderDO::getAreaNamePrefix)).forEach((areaName, areaOrderList) -> {
            if (CollectionUtils.isNotEmpty(areaOrderList)) {
                Long count = 0L;
                for (DishOrderDO dishOrderDO : areaOrderList) {
                    List<DishOrderSubDO> dishOrderSubDOList = dishOrderSubService.lambdaQuery()
                            .eq(DishOrderSubDO::getOrderId, dishOrderDO.getId())
                            .list();
                    for (DishOrderSubDO dishOrderSubDO : dishOrderSubDOList) {
                        List<DishOrderBookDO> list = dishOrderBookService.lambdaQuery()
                                .eq(DishOrderBookDO::getOrderId, dishOrderDO.getId())
                                .eq(DishOrderBookDO::getSubOrderId, dishOrderSubDO.getId())
                                .list();
                        for (DishOrderBookDO dishOrderBookDO : list) {
                            count = count + dishOrderBookDO.getBookNum();
                        }
                    }
                }
                DishOrderSubAreaStatisticsVO vo = new DishOrderSubAreaStatisticsVO();
                vo.setAreaName(areaName);
                vo.setCount(count);
                dishOrderSubAreaStatisticsVOS.add(vo);
            }
        });
        return dishOrderSubAreaStatisticsVOS;
    }
}
